/*  This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or (at
    your option) any later version.
    For more details, see the GNU Lesser General Public License (www.fsf.org
    or the COPYING file somewhere in the package)
 */

/*! @file test/Valid.cc
    @brief Main program.
    @author @ref Guillaume_Terrissol
    @date 15th February 2010 - 29th January 2014
    @note This file is distributed under the LGPL license.
    Refer to the file COPYING (or http://www.fsf.org) for more information.
 */

#include <cstdlib>
#include <ctime>
#include <fstream>

#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextTestProgressListener.h>
#include <cppunit/XmlOutputter.h>
#include <cppunit/XmlOutputterHook.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/tools/XmlDocument.h>
#include <cppunit/tools/XmlElement.h>
#include <cppunit/ui/text/TestRunner.h>

#include <OSGi.hh>

#include "Utils.hh"

namespace CHK
{
//------------------------------------------------------------------------------
//                                     Hook
//------------------------------------------------------------------------------

    /*! @brief This "hook" allows adding information into the validation report.
        @version 0.6
     */
    class AddContextHook : public CppUnit::XmlOutputterHook
    {
    public:
        //! @name Interface
        //@{
virtual         ~AddContextHook();                                          //!< Destructor.
virtual void    beginDocument(CppUnit::XmlDocument* pDocument) override;    //!< Header addition.
        //@}
    };


//------------------------------------------------------------------------------
//                              Hook : "Interface"
//------------------------------------------------------------------------------

    /*! Defaulted.
     */
    AddContextHook::~AddContextHook() = default;


    /*! This methods adds a few pieces of information into the report header.
        @param pDocument Validation report, as XML document
     */
    void AddContextHook::beginDocument(CppUnit::XmlDocument* pDocument)
    {
        if (pDocument == 0)
        {
            return;
        }

        // Versions.
        CppUnit::XmlElement* lContext = new CppUnit::XmlElement("Context", "");
        lContext->addAttribute("Version", VALID_VERSION);

        std::string lCompiler   = CommandDump{"g++ -dumpversion"}.output();
        lContext->addAttribute("Compiler", !lCompiler.empty() ? lCompiler : std::string{"unknown"});

        std::string lSystem     = CommandDump{"uname -s"}.output();
        lContext->addAttribute("System", !lSystem.empty() ? lSystem : std::string{"unknown"});

        std::string lRelease    = CommandDump{"uname -r"}.output();
        lContext->addAttribute("Release", !lRelease.empty() ? lRelease : std::string{});

        lContext->addAttribute("OSGi", OSGI_VERSION);

        // Time and Date.
        time_t      lRawtime;
        struct tm*  lTimeInfo;

        time(&lRawtime);
        lTimeInfo = localtime(&lRawtime);

        std::string lBuffer(100, ' ');
        strftime(&lBuffer[0], 100, "%Y-%m-%dT%H:%M:%S", lTimeInfo);
        lContext->addAttribute("Date", lBuffer.c_str());    // Keep .c_str() !

        pDocument->rootElement().addElement(lContext);
    }
}

//------------------------------------------------------------------------------
//                                    main()
//------------------------------------------------------------------------------

extern "C" int main(int, char*[])
{
    CppUnit::TestResult                 lResult;
    CppUnit::TestResultCollector        lCollector;     // Results retrieving.
    lResult.addListener(&lCollector);
    CppUnit::TextTestProgressListener   lProgressor;    // Results trace.
    lResult.addListener(&lProgressor);
    CppUnit::TestRunner                 lRunner;
    lRunner.addTest(CppUnit::TestFactoryRegistry::getRegistry("Miscellaneous tests").makeTest());
    lRunner.addTest(CppUnit::TestFactoryRegistry::getRegistry("Standard tests").makeTest());
    lRunner.addTest(CppUnit::TestFactoryRegistry::getRegistry("Checking services").makeTest());
    lRunner.addTest(CppUnit::TestFactoryRegistry::getRegistry("Bundle life cycle").makeTest());

    // Here we go
    lRunner.run(lResult);

    // Builds a test report.
    {
        std::ofstream           lFile{"Report.xml"};
        CppUnit::XmlOutputter   lXml{&lCollector, lFile};
        CHK::AddContextHook     lHook;
        lXml.addHook(&lHook);
        lXml.setStyleSheet("Report.xsl");
        lXml.write();
    }

    // Returns error code 1 if one of the tests failed.
    return lCollector.wasSuccessful() ? 0 : 1;
}
